/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "FileDownload.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>

#include "Progress.h"
#include "FileUtil.h"

using namespace Bio;

const int	c_bufferSize = 65536;

const QString	c_tempExt = ".tmp";

QNetworkAccessManager*	FileDownload::s_mgr = NULL;

/**
**/
FileDownload::FileDownload() : m_reply( NULL ), m_buffer( NULL ), m_progress( NULL )
{
}

/**
**/
FileDownload::FileDownload( const QString &filename ) : m_filename( filename ), m_reply( NULL ), 
	m_buffer( NULL ), m_progress( NULL )
{
}

/**
**/
FileDownload::~FileDownload()
{
}

/**
**/
void FileDownload::setFilename( const QString &filename )
{
	m_filename = filename;
}

/**
**/
bool FileDownload::startDownload( const QString &url )
{
	return startDownload( QUrl( url ) );
}

/**
**/
bool FileDownload::startDownload( const QUrl &url )
{
	if( !startup() )
		return false;

	m_reply = s_mgr->get( QNetworkRequest( url ) );

	connect( m_reply, SIGNAL(finished()), this, SLOT(finish()) );
	connect( m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(downloadProgress(qint64,qint64)) );
	connect( m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleError(QNetworkReply::NetworkError)) );
	connect( m_reply, SIGNAL(readyRead()), this, SLOT(dataReady()) );

	return true;
}

/**
**/
bool FileDownload::downloadSynchronous( const QString &url )
{
	return downloadSynchronous( QUrl( url ) );
}

/**
**/
bool FileDownload::downloadSynchronous( const QUrl &url )
{
	if( !startup() )
		return false;

	bool		status = true;
	Progress	progress( QString( "Downloading file %1..." ).arg( FileUtil::getFilename( m_filename ) ), 200 );

	m_progress = &progress;

	m_reply = s_mgr->get( QNetworkRequest( url ) );
	connect( m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(handleProgress(qint64,qint64)) );

	while( !m_reply->isFinished() ){
		while( m_reply->bytesAvailable() ){
			qint64	bytesRead = m_reply->read( m_buffer, c_bufferSize );

			m_file.write( m_buffer, bytesRead );
		}

		qApp->processEvents();
		
		if( progress.isCanceled() ){
			m_reply->abort();
			status = false;
			break;
		}
	}

	if( status )
		status = cleanup();

	progress.finish();
	m_progress = NULL;

	return status;
}

/**
**/
void FileDownload::dataReady()
{
	while( m_reply->bytesAvailable() ){
		qint64	bytesRead = m_reply->read( m_buffer, c_bufferSize );
		
		m_file.write( m_buffer, bytesRead );
	}
}

/**
**/
void FileDownload::handleError( QNetworkReply::NetworkError code )
{
	emit error( code );
}

/**
**/
void FileDownload::finish()
{
	dataReady(); // flush any remaining data
	cleanup();

	emit finished();
}

/**
**/
void FileDownload::handleProgress( qint64 bytesReceived, qint64 bytesTotal )
{
	if( !m_progress )
		return;

	if( bytesTotal < 0 ){
		m_progress->step();
		return;
	}

	m_progress->update( (bytesReceived * 200) / bytesTotal );
}

/**
**/
bool FileDownload::startup()
{
	if( m_filename.isEmpty() )
		return false;

	m_file.setFileName( m_filename + c_tempExt );

	if( !m_file.open( QIODevice::WriteOnly ) )
		return false;

	if( !s_mgr )
		s_mgr = new QNetworkAccessManager();

	m_buffer = new char[c_bufferSize];

	return true;
}

/**
**/
bool FileDownload::cleanup()
{
	QDir	dir;

	m_file.close();

	delete m_reply;
	m_reply = NULL;

	delete m_buffer;
	m_buffer = NULL;

	if( !dir.rename( m_filename + c_tempExt, m_filename ) )
		return false;

	return true;
}
